using System;
using System.IO;					// Zur Arbeit mit Datei
using System.Collections.Generic;	// Grundlegende Datenstrukturen

namespace GraphSpace
{
	public class oldGraph
	{
		// Liste der Knoten
		private List<Knoten> v;
		
		// ungerichtete Kanten :: Zugriff Start-Knoten ID -> Zugriff Ziel-Knoten ID -> Kante
		private	Dictionary<int, List<Kante>> e;
		// gerichtete Kanten :: Zugriff Start-Knoten ID -> Zugriff Ziel-Knoten ID -> Kante
		private	Dictionary<int, List<Kante>> a;
		// gerichtete inverse Kanten :: Zugriff Start-Knoten ID -> Zugriff Ziel-Knoten ID -> Kante
		private	Dictionary<int, List<Kante>> ar;
		
		private int n, m;			// Anzahl der Kanten und Knoten
		
		/// <summary>Standardkonstruktor</summary> 
		public oldGraph ()
		{
			n = 0;
			m = 0;
			v = new List<Knoten>();
			e = new Dictionary<int, List<Kante>>();
			a = new Dictionary<int, List<Kante>>();
			ar = new Dictionary<int,List<Kante>>();
		}
	
		/// <summary>Methode zum Einfügen eines neuen Knotens</summary>
		/// <returns>false, wenn Knoten bereits im Graphen vorhanden ist</returns>
		/// <param name="id">ID des einzufügenden Knotens</param>
		/// <param name="daten">Daten am Knoten</param>
		public bool neuerKnoten(int id)
		{
			// Prüfe, ob Knoten bereits vorhanden ist
			if(!enthaeltKnoten(id))
			{
				v.Add(new Knoten(id));				// Knoten aufnehmen
				e.Add(id, new List<Kante>());				// Adjazensliste für Knoten anlegen (ungerichtet)
				a.Add(id, new List<Kante>());				// Adjazensliste für Knoten anlegen (gerichtet)
				ar.Add(id, new List<Kante>());				// Adjazensliste für Knoten anlegen (gerichtet invers)
				n++;
				//Console.WriteLine("Knoten "+id+" eingefügt");
			}
			
			// Knoten bereits vorhanden, wurde nicht eingefügt
			return false;
		}
		
		/// <summary>Methode zum EInfügen einer neuen Kante (auch parallel).</summary>
		/// <param name="von">ID des Startknotens</param>
		/// <param name="nach">ID des Zielknotens</param>
		/// <param name="gewicht">Kantengewicht</param>
		/// <returns>false, wenn einer der beiden Knoten nicht im Graphen vorhanden</returns>
		public bool neueKante(int von, int nach, double gewicht)
		{
			Knoten e1 = holeKnoten(von);
			Knoten e2 = holeKnoten(nach);
			// Prüfe, ob die Knoten vorhanden
			if(e1!=null && e2!=null)		
			{
				// ungerichtet
				e[von].Add(new Kante(e1, e2, gewicht));		// Kante in Adjazensliste des Start-Knotens einfügen
				e[nach].Add(new Kante(e2, e1, gewicht));		// Kante in Adjazensliste des Start-Knotens einfügen (2. Richtung)
								
				// gerichtet
				a[von].Add(new Kante(e1, e2, gewicht));		// Kante in Adjazensliste des Start-Knotens einfügen
				ar[nach].Add(new Kante(e2, e1, gewicht));	// Kante in Adjazensliste des Start-Knotens einfügen (invers)
				
				//Console.WriteLine("Kante von "+von+" nach "+nach+" eingefügt");
				m++;
				
				return true;
			}
			
			return false;		// Knoten war noch nicht vorhanden
		}
	
		/// <summary>Abfrage, ob Knoten mit ID im Graphen vorhanden ist</summary>
		/// <param name="id">ID des Knotens</param>
		/// <returns>true, wenn Knoten im Graphen vorhanden</returns>
		public bool enthaeltKnoten(int id)
		{
			foreach(Knoten vi in v)
				if(vi.Id == id)
					return true;
			
			return false;
		}
	
		public Knoten holeKnoten(int id)
		{
			foreach(Knoten vi in v)
				if(vi.Id == id)
					return vi;
			
			return null;
		}
			
		/// <summary>Ruft die reset-Methode auf allen Knoten des Graphen auf 
		/// und setzt damit deren Attribute für Algorithmen zurück</summary>
		public void resetV()
		{
			foreach(Knoten w in v)
				w.reset();
		}
		
		/// <summary>Methode zum Einlesen eines Graphen aus Datei. 
		/// Dabei werden alle zuvor gesetzten Knoten und Kanten entfernt</summary>
		/// <param name="pfad">Pfad zur Datei</param>
		/// <returns>false, wenn Datei nicht eingelesen werden konnte</returns>
		public bool ladeGraph(string pfad)
		{
			string zeile="";
			if (File.Exists(pfad))
			{
				// Graph leeren				
				v = new List<Knoten>();
				e = new Dictionary<int, List<Kante>>();
				a = new Dictionary<int, List<Kante>>();
				ar = new Dictionary<int,List<Kante>>();
				
				// Datei einlesen
				StreamReader reader = new StreamReader(pfad, System.Text.Encoding.Default);
				zeile = reader.ReadLine();		// erste Zeile mit Basiswerten einlesen und verwerfen
				
				while(!reader.EndOfStream)
				{
					zeile = reader.ReadLine();
					if(zeile.Split(' ').GetLength(0) > 1)
					{
						int e1 = Convert.ToInt32(zeile.Split(' ')[1]);		// Startknoten der Kante
						neuerKnoten(e1);
						int e2 = Convert.ToInt32(zeile.Split(' ')[2]);		// Zielknoten der Kante
						neuerKnoten(e2);
						
						neueKante(e1, e2, 0.0);								// Kante einfügen
					}
				}
				
				reader.Close();
				//Console.WriteLine("Graph geladen");
				return true;
			  }

			return false;
		}
		
		public bool speicherGraph(string pfad)
		{	
			try
			{
				// Datei einlesen
				StreamWriter writer = new StreamWriter(pfad);
				writer.WriteLine("n " + v.Count + " m " + m);
					
				foreach(Knoten w in v)
					foreach(Kante e in a[w.Id])
						writer.WriteLine("e "+ e.Von + " " + e.Nach);
				
				writer.Close();
				Console.WriteLine("Graph gespeichert");
				return true;
			}
			catch
			{
				return false;
			}			
		}
		
		// get-Methoden
		public int N
		{
			get{return this.n;}
		}
		public int M
		{
			get{return this.m;}
		}
		public List<Knoten> V
		{
			get{return this.v;}
		}	
		public Dictionary<int, List<Kante>> E
		{
			get{return this.e;}
		}
		public Dictionary<int, List<Kante>> A
		{
			get{return this.a;}
		}
		public Dictionary<int, List<Kante>> Ar
		{
			get{return this.ar;}
		}
	}
}
